package com.dsjy.yf.address.service.impl;

import com.dsjy.yf.address.config.base.BizException;
import com.dsjy.yf.address.config.base.CommonEnum;
import com.dsjy.yf.address.entity.SplitResult;
import com.dsjy.yf.address.service.AddressSplitService;
import com.dsjy.yf.address.service.BatchProcessService;
import com.dsjy.yf.address.utils.CSVUtils;
import com.dsjy.yf.address.utils.DownLoadUtil;
import com.dsjy.yf.address.utils.FileUtil;
import com.dsjy.yf.address.utils.MyStringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;

/**
 * @author whj
 * @version 1.0
 * @date 2021-01-23 11:27
 */
@Slf4j
@Service
public class BatchProcessServiceImpl implements BatchProcessService {


    private static final String XLS = ".xls";
    private static final String XLSX = ".xlsx";
    private static final String SEPARATION = "%&#";

    private static final String RESULT_NAME = "处理结果.csv";
    @Autowired
    private AddressSplitService addressSplitService;

    @Override
    public void processWithExcel(InputStream in, String fileName, HttpServletResponse response) {
        OutputStream outputStream = null;
        try (Workbook workbook = batchSplitProcess(in, fileName)) {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            response.flushBuffer();
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
        } catch (IOException e) {
            throw new BizException(11, e.getMessage());
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void processWithCsv(MultipartFile file, String fileName, HttpServletResponse response) throws IOException {
        String dirPath = FileUtil.TEM_PATH + Thread.currentThread().getId() + "/";
        try {
            File localFile = CSVUtils.uploadFile(file, dirPath);
            Integer num = FileUtil.splitCSVFile(dirPath, localFile);
            log.info("文件拆分完毕====>" + dirPath + "===" + num);
            if (num != null && num > 0) {
                String resultPathName = FileUtil.creatModelCSVfile(dirPath + RESULT_NAME);
                for (int i = 1; i <= num; i++) {
                    log.info("****************************************" + i + "*******************************************");
                    List<String> addressList = FileUtil.getAddressList(dirPath + i);
                    if (addressList != null && addressList.size() > 0) {
                        splitAddressToCSV(addressList, resultPathName);
                    }
                }
                CSVUtils.downloadFile(response, dirPath, RESULT_NAME);
                log.info("======结果已返回======");
            }
        } finally {
            FileUtil.deleteFile(dirPath);
        }
    }

    @Override
    public Workbook batchSplitProcess(InputStream in, String fileName) throws IOException {
        List<String> list = getAddressListWithSheet(in, fileName);
        SXSSFWorkbook workbook = DownLoadUtil.getModelWorkbool();
        if (workbook != null) {
            splitWithSheet(workbook.getSheetAt(0), list);
        }
        return workbook;
    }

    private void splitAddressToCSV(List<String> list, String pathName) throws IOException {
        Path path = Paths.get(pathName);
        SplitResult result = null;
        String line = null;
        String[] strArray = null;
        String id = null;
        String address = null;
        try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)) {
            int index = 0;
            for (String item : list) {
                strArray = item.split(SEPARATION);
                id = strArray[0];
                address = strArray[1];
                if (address.length() <= 3) {
                    result = null;
                } else {
                    result = addressSplitService.splitAddress(address);
                }
                line = CSVUtils.generateCSVLine(result, id, address);
                writer.write(line);
                index++;
                if (index % 50000 == 0) {
                    System.gc();
                }
            }
            writer.flush();
            list = null;
            System.gc();
        }
    }

    /**
     * 从上传文件中获取地址列表
     *
     * @param in
     * @param fileName
     * @return
     * @throws IOException
     */
    private List<String> getAddressListWithSheet(InputStream in, String fileName) throws IOException {
        Workbook workbook = null;
        Sheet sheet = null;
        List<String> addressList = null;
        Row row = null;
        String id = null;
        String address = null;
        try {
            if (fileName.endsWith(XLS)) {
                workbook = new HSSFWorkbook(in);
            } else if (fileName.endsWith(XLSX)) {
                workbook = new XSSFWorkbook(in);
            }
            if (workbook == null) {
                throw new BizException(CommonEnum.UNKNOWN_ERROR);
            }
        } finally {
            if (in != null) {
                in.close();
            }
        }
        sheet = workbook.getSheetAt(0);
        addressList = new ArrayList<>(sheet.getLastRowNum());
        for (int i = 2; i <= sheet.getLastRowNum(); i++) {
            row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            try {
                id = getCellValue(row.getCell(0));
                address = MyStringUtil.emptyToNull(row.getCell(1).getStringCellValue());
            } catch (Exception e) {
                continue;
            }
            if (id == null || address == null) {
                continue;
            }
            addressList.add(id + SEPARATION + address);
        }
        return addressList;
    }


    /**
     * 拆分地址并插入到sheet中
     *
     * @param sheet
     * @param list
     * @throws IOException
     */
    private void splitWithSheet(SXSSFSheet sheet, List<String> list) throws IOException {
        SplitResult result = null;
        String address = null;
        int i = 1;
        for (String originalAddress : list) {
            if (i % 30000 == 0) {
                Runtime.getRuntime().gc();
            }
            String[] arr = originalAddress.split(SEPARATION);
            if (arr.length < 2) {
                continue;
            }
            address = arr[1];
            i++;
            Row row = sheet.createRow(i);
            row.createCell(0).setCellValue(arr[0]);
            row.createCell(1).setCellValue(address);
            try {
                result = addressSplitService.splitAddress(address);
            } catch (Exception e) {
                log.error("address:" + address + "---" + e.getMessage());
                continue;
            }
            if (result != null) {
                fillRow(result, row);
            }
        }
    }

    /**
     * 将拆分结果插入到对应行中
     *
     * @param result
     * @param row
     */
    private void fillRow(SplitResult result, Row row) {
        row.createCell(2).setCellValue("浙江省");
        row.createCell(3).setCellValue("温州市");
        if (result.getCounty() != null) {
            row.createCell(4).setCellValue(result.getCounty());
        }
        if (result.getTown() != null) {
            row.createCell(5).setCellValue(result.getTown());
        }
        if (result.getExclusivezone() != null) {
            row.createCell(6).setCellValue(result.getExclusivezone());
        }
        if (result.getCommunity() != null) {
            row.createCell(7).setCellValue(result.getCommunity());
        }
        if (result.getVillage() != null) {
            row.createCell(8).setCellValue(result.getVillage());
        }
        if (result.getStreet() != null) {
            row.createCell(9).setCellValue(result.getStreet());
        }
        if (result.getDoor() != null) {
            row.createCell(10).setCellValue(result.getDoor());
        }
        if (result.getYardName() != null) {
            row.createCell(11).setCellValue(result.getYardName());
        }
        if (result.getYardAlias() != null) {
            row.createCell(12).setCellValue(result.getYardAlias());
        }
        if (result.getSubareaName() != null) {
            row.createCell(13).setCellValue(result.getSubareaName());
        }
        if (result.getSubareaAlias() != null) {
            row.createCell(14).setCellValue(result.getSubareaAlias());
        }
        if (result.getInternalRoad() != null) {
            row.createCell(15).setCellValue(result.getInternalRoad());
        }
        if (result.getInternalDoor() != null) {
            row.createCell(16).setCellValue(result.getInternalDoor());
        }
        if (result.getBuildingNum() != null) {
            row.createCell(17).setCellValue(result.getBuildingNum());
        }
        if (result.getUnit() != null) {
            row.createCell(18).setCellValue(result.getUnit());
        }
        if (result.getFloor() != null) {
            row.createCell(19).setCellValue(result.getFloor());
        }
        if (result.getHomeNum() != null) {
            row.createCell(20).setCellValue(result.getHomeNum());
        }
        if (result.getPoi() != null) {
            row.createCell(21).setCellValue(result.getPoi());
        }
        if (result.getBuildingName() != null) {
            row.createCell(22).setCellValue(result.getBuildingName());
        }
        if (result.getBuildingAlias() != null) {
            row.createCell(23).setCellValue(result.getBuildingAlias());
        }
        if (result.getRest() != null) {
            row.createCell(24).setCellValue(result.getRest());
        }

    }

    /**
     * 获取Excel单元格中的数据并转化为String类型
     *
     * @param cell
     * @return
     */
    public String getCellValue(Cell cell) {
        CellType cellType = cell.getCellType();
        switch (cellType) {
            case STRING:
                return MyStringUtil.emptyToNull(cell.getStringCellValue());
            case NUMERIC: {
                try {
                    return MyStringUtil.emptyToNull(String.valueOf((int) cell.getNumericCellValue()));
                } catch (Exception e) {
                    return null;
                }
            }
            default:
                return null;
        }
    }
}
